<?php
/*****************************************************

  Copyright:	(c) 2006  SeaDesign Web Studio
        Web:	www.seadesign.ru
      Email: 	seadesign@gmail.com
  
*****************************************************/

require_once('params.inc');
require_once('db.inc');
require_once('controls.inc');
require_once('data.inc');


function getString($name) 
{
	global $db, $lang;
	
	$q = new Select($db, 'cf_strings');
	$q->addFields('txt');
	$q->where('name',$name);
	$q->where('lang',$lang);
	$q->run();
	if (!$q->fetch()) {
		return $name;
	}
	return $q->at(0);
}


define('ROOT_PAGE',null);


class SitePage
{

	function __construct($id, $parent, $name, $menuName, $link, $title=null, $keywords=null, $descr=null, $text=null, $image=null) 
	{
		$this->id = $id;
		$this->parent = $parent;
		$this->name = $name;
		$this->menuName = $menuName;
		$this->title = $title;
		$this->keywords = $keywords;
		$this->descr = $descr;
		$this->text = $text;
		$this->image = $image;
		$this->hasCustomLink = (bool)strlen($link);
		$this->link = $link;
	}


	public function id()
	{
		return $this->id;
	}

	public function parent() 
	{
		return $this->parent;
	}
	
	public function name() 
	{
		return $this->name;
	}

	public function menuName() 
	{
		return $this->menuName;
	}

	public function isCustom() 
	{
		return $this->hasCustomLink;
	}	
	
	public function link() 
	{
		return $this->link;
	}
	
	public function title() 
	{
		if (!$this->title) {
		   return $this->name();
		}
		return $this->title;
	}
	
	public function keywords() 
	{
		return $this->keywords;
	}
	
	public function descr() 
	{
		return $this->descr;
	}
	
	public function text() 
	{
		return $this->text;
	}
	
	public function image()
	{
		return $this->image;
	}

	
	protected $id = null;
	protected $code = null;
	protected $parent = null;
	protected $name = null;
	protected $menuName = null;
	protected $link = null;
	protected $text = null;
	protected $title = null;
	protected $keywords = null;
	protected $descr = null;
	protected $image = null;
	protected $hasCustomLink = null;
}



class Page 
	extends SitePage
{
	static public $basePageURL = 'page.php';
	
	static public function get($id)
	{
		if (self::$friendlyURLS == self::USE_HIERARCICAL_FRIENDLY_URLS)
		{
			$id = String::lastWord($id,'/');
		}
		return new Page($id);
	}
	
	function __construct($id) 
	{
		global $db, $lang;
		
		$id = self::toID($id);
		
		$q = new Select($db, 'cf_pages');
		$q->addFields('parent','name','menu_name','link','title','keywords','descr','icon','code');
		$q->where('id', $id);
		$q->where('lang', $lang);
		$q->run();
		
		if ($q->fetch(DB_FETCH_ASSOC)) 
		{
			$code = $q->at('code');
			parent::__construct(
				$code ? $code : $id, 
				$q->at('parent'), 
				$q->at('name'), 
				$q->at('menu_name'), 
				$q->at('link'),
				$q->at('title'),
				$q->at('keywords'),
				$q->at('descr'),
				null,
				$q->at('icon')
			);
		}
		else 
		{
			throw new Exception("Page with id[$id] not found");
		}
	}
	
	public function text() 
	{
		if (null === $this->text) 
		{
			global $db, $lang;
			
			$q = new Select($db, 'cf_pages');
			$q->addFields('txt');
			$q->where('lang', $lang);
			$q->where('id', self::toID($this->id()));
			$q->run();
			$q->fetch();
			$this->text = $q->at(0);
		}
		return $this->text;
	}
	
	public function nestingDepth()
	{
		if (!is_null($this->nestingDepth)) {
			return $this->nestingDepth;
		}
		
		$this->nestingDepth = 0;
		
		$id = $this->parent();
		while ($id != ROOT_PAGE)
		{
			++$this->nestingDepth;
			$page = new Page($id);
			$id = $page->parent();
		}
		
		return $this->nestingDepth;
	}
	
	
	/**
		@param $id  string CODE or numeric ID
		@return numeric ID
	*/
	static public function toID($id)
	{
		global $lang;
		
		if (is_numeric($id)) {
			return (int)$id;
		}
		
		if (is_null($id)) {		//root page
			return $id;
		}

		static $q = null;
		createStaticQuery($q,"
			SELECT id FROM cf_pages WHERE code=:code AND lang=:lang
		");
		$q->setParam('code',trim($id));
		$q->setParam('lang',$lang);
		$q->execute();
		if (!$q->fetch()) {
			throw new Exception("Invalid page code: [$id]");
		}
		$id = (int)$q->at(0);
		$q->close();
		
		return $id;
	}
	
	public function link() 
	{
		if ($this->isCustom()) {
			return $this->link;
		}
		
		if (self::$friendlyURLS == self::USE_FRIENDLY_URLS)
		{
			return "/{$this->id}";
		}
		
		if (self::$friendlyURLS == self::USE_HIERARCICAL_FRIENDLY_URLS)
		{
			$ancestors = new AncestorPages($this->id);
			return '/'.implode('/',array_merge($ancestors->IDs(),array($this->id)));
		}

		return self::createLink($this->id);
	}
	
	public function isAncestorOf($id)
	{
		$allAncestors = new AncestorPages($id);
		return in_array($this->id(), $allAncestors->IDs());
	}
	
	const NO_FRIENDLY_URLS = 0;
	const USE_FRIENDLY_URLS = 1;
	const USE_HIERARCICAL_FRIENDLY_URLS = 2;
	
	/**
		@param  $use Page::USE_FRIENDLY_URLS | Page::USE_HIERARCICAL_FRIENDLY_URLS
	*/
	static public function useFriendlyURLs($use=Page::USE_FRIENDLY_URLS)
	{
		self::$friendlyURLS = $use;
	}
	
	static private $friendlyURLS = 0;
	
	
	static private function createLink($id)
	{
		$link = new URL(self::$basePageURL);
		$link->setParam('id', $id);
		return (string)$link;
	}
	
	
	private $nestingDepth = null;
}




class Pages 
	extends ArrayOfItems
{
	public function IDs()
	{
		$IDs = array();
		foreach ($this->items as $page) 
		{
			$IDs[] = $page->id();
		}
		return $IDs;
	}
	
	/**
		Menu tree of pages
		@return  array(pageId => array(name,link,image,depth)) parent page first, then descendants
	*/
	static public function toHierarchyTree($rootId=ROOT_PAGE)
	{
		$tree = array();
		$children = new ChildPages($rootId);
		for ($i=0; $i<$children->size(); ++$i)
		{
			$child = $children->at($i);
			
			$descendants = self::toHierarchyTree($child->id());
			$tree[(string)$child->id()] = array(
				'id'   => $child->id(),
				'name' => $child->menuName(),
				'link' => $child->link(),
				'image' => $child->image(),
				'depth' => $child->nestingDepth(),
				'isFirstChild' => (bool)($i==0),
				'isLastChild' => (bool)($i==$children->size()-1),
				'hasChildren' => !empty($descendants)
			);
			$tree = array_merge($tree, $descendants);
		}
		return $tree;
	}
	
	/**
		@return array( array(name,link) ) of ancestor pages + this page
	*/
	static public function getPath($pageId)
	{
		$path = array();
		$ancestors = new AncestorPages($pageId);
		foreach ($ancestors as $page)
		{
			$path[] = array(
				'name' => $page->menuName(),
				'link' => $page->link()
			);
		}
		$page = new Page($pageId);
		$path[] = array(
			'name' => $page->menuName(),
			'link' => $page->link()
		);
		return $path;
	}
	

	protected function add(SitePage $page) 
	{
		parent::add($page);
	}
};



class ChildPages 
	extends Pages
{
	function __construct($parentId)
	{
		global $db, $lang;
		
		$parentId = Page::toID($parentId);
		
		$q = new Select($db,'cf_pages');
		$q->addFields('id');
		$q->where('parent',$parentId);
		$q->where('lang',$lang);
		$q->addWhereString('cf_pages.hide IS NULL OR cf_pages.hide=0');
		$q->order('menu_pos',ASC);
		$q->run();
		
		while ($q->fetch()) {
			$this->add( new Page($q->at(0)) );
		}
	}
}


class DescendantPages
	extends Pages
{
	function __construct($parentId)
	{
		$this->addChildren($parentId);
	}
	
	
	private function addChildren($parentId)
	{
		$children = new ChildPages($parentId);
		foreach ($children as $child) 
		{
			$this->add($child);
			$this->addChildren($child->id());
		}
	}
}


/**
 [0]grandparent [1]parent 
*/
class AncestorPages
	extends Pages
{
	function __construct($id)
	{
		while ($id != ROOT_PAGE)
		{                                            
			$page = new Page($id);
			$id = $page->parent();
			if ($id != ROOT_PAGE) {
				$page = new Page($id);
				$this->add($page);
			}                                         
		}
		$this->items = array_reverse($this->items);
	}
}



/**
   AncestorPages + this page
*/
class BranchPages
	extends AncestorPages
{
	function __construct($id)
	{
		parent::__construct($id);
		$this->add(new Page($id));
	}
}

?>